package com.faxsun.core.util.service;

import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.common.time.SystemTime;
import org.broadleafcommerce.common.util.StreamCapableTransactionalOperationAdapter;
import org.broadleafcommerce.core.catalog.dao.SkuDao;
import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.core.order.domain.OrderItem;
import org.broadleafcommerce.core.util.service.ResourcePurgeServiceImpl;
import org.broadleafcommerce.core.util.service.type.PurgeCartVariableNames;
import org.broadleafcommerce.profile.core.domain.Customer;
import org.springframework.transaction.annotation.Transactional;

import com.faxsun.core.catalog.domain.FSSku;
import com.faxsun.core.order.domain.FSOrderImpl;
import com.faxsun.core.order.domain.FSOrderItemImpl;
import com.faxsun.core.order.service.type.FSInternalOrderStatus;
import com.faxsun.core.order.service.type.FSOrderStatus;

public class FSResourcePurgeServiceImpl extends ResourcePurgeServiceImpl {

	private static final Log LOG = LogFactory
			.getLog(FSResourcePurgeServiceImpl.class);
	
	private static final long fifteenDays=15L * 24 * 60 * 60 * 1000;
	private static final long sevnthFiveMinutes=75L*60*1000;

	@Resource(name = "blSkuDao")
	protected SkuDao skuDao;

	@Override
	public void purgeCarts(final Map<String, String> config) {
		if (LOG.isDebugEnabled()) {
			LOG.debug("Purging carts");
		}
		if (MapUtils.isEmpty(config)) {
			throw new IllegalArgumentException(
					"Cannot purge carts since there was no configuration provided. "
							+ "In the absence of config params, all carts would be candidates for deletion.");
		}
		try {
			// The removal will be performed in chunks based on page size. This
			// minimizes transaction times.
			transUtil.runStreamingTransactionalOperation(
					new StreamCapableTransactionalOperationAdapter() {
						@Override
						public void pagedExecute(Object[] param)
								throws Throwable {
							@SuppressWarnings("unchecked")
							List<Order> orders = (List<Order>) param[0];
							for (Order cart : orders) {
								deleteCart(cart);
							}
						}

						@Override
						public Object[] retrievePage(int startPos, int pageSize) {
							List<Order> results = getCartsToPurge(config,
									startPos, pageSize);
							return new Object[] { results };
						}

						@Override
						public Long retrieveTotalCount() {
							return getCartsToPurgeLength(config);
						}

						@Override
						public boolean shouldRetryOnTransactionLockAcquisitionFailure() {
							return true;
						}
					}, RuntimeException.class);
		} catch (Exception e) {
			LOG.error("Unable to purge carts inFSResourcePurgeService", e);
		}
	}

	/**
	 * Remove the cart from the persistence layer. Subclasses may override for
	 * custom cart retrieval logic.
	 *
	 * @param cart
	 *            the cart to remove
	 */
	@Override
	@Transactional("blTransactionManager")
	protected void deleteCart(Order cart) {
		// We delete the order this way (rather than with a delete query) in
		// order to ensure the cascades take place
		try {
			List<OrderItem> items = cart.getOrderItems();
			boolean isTreasure = false;// 包含夺宝类产品
			for (OrderItem item : items) {
				if (item.getCategory().getUrl().contains("/treasure")) {
					isTreasure = true;
				}
			}

			boolean isDeleted = false;
			Date date = cart.getAuditable().getDateUpdated();
			Date createdTime = cart.getAuditable().getDateCreated();
			if (date == null) {
				date = createdTime;
			}
			Long updateTime = date.getTime();
			Long curr = System.currentTimeMillis();

			if (isTreasure) {
				// 夺宝类产品，在购物车中，75分钟内未完成支付，则删除
				if ((curr - updateTime) > sevnthFiveMinutes) { // double check
				// if ((curr - updateTime) > 60 * 1000) {test
					isDeleted = true;
					FSOrderImpl order = (FSOrderImpl) cart;
					if ((order.getInternalStatus() != null && order
							.getInternalStatus().equals(
									FSInternalOrderStatus.PAYMENT_IN_PROCESS))) {
						//订单状态为IN_PROCESS,夺宝类不需要回滚库存，因为库存在点击去支付后才减库存
						//increaseInventory(items);
					}
				}

			} else {
				Customer customer = cart.getCustomer();
				// 其他产品，匿名用户超过超过15天购物车删除
				if ((customer == null || customer.isAnonymous())
						&& ((curr - updateTime) > fifteenDays)) {
					isDeleted = true;
				}
			}

			if (isDeleted) {
				orderService.deleteOrder(cart);
			}
		} catch (Exception e) {
			LOG.error("Unable to purge a cart", e);
		}
	}

	@SuppressWarnings("unused")
	private void increaseInventory(List<OrderItem> items) {
		// 回滚库存
		for (OrderItem item : items) {
			FSOrderItemImpl fsItem = (FSOrderItemImpl) item;
			FSSku sku = (FSSku) fsItem.getSku();

			sku.setQuantityAvailable(sku.getQuantityAvailable() + 1);
			skuDao.save(sku);
		}

	}

	/**
	 * Remove the cart from the persistence layer. Subclasses may override for
	 * custom cart retrieval logic.
	 *
	 * @param customer
	 *            the customer to remove
	 */
	protected void deleteCustomer(Customer customer) {
		// We delete the customer this way (rather than with a delete query) in
		// order to ensure the cascades take place
		try {
			LOG.warn("Delete customer [id=" + customer.getId() + "]");
			customerService.deleteCustomer(customer);
		} catch (Exception e) {
			LOG.error("Unable to purge a customer", e);
		}
	}

	@SuppressWarnings("unused")
	private class CartPurgeParams {

		private Map<String, String> config;
		private String[] nameArray;
		private FSOrderStatus[] statusArray;
		private Date dateCreatedMinThreshold;
		private Boolean isPreview;

		public CartPurgeParams(Map<String, String> config) {
			this.config = config;
		}

		public String[] getNameArray() {
			return nameArray;
		}

		public FSOrderStatus[] getStatusArray() {
			return statusArray;
		}

		public Date getDateCreatedMinThreshold() {
			return dateCreatedMinThreshold;
		}

		public Boolean getIsPreview() {
			return isPreview;
		}

		public CartPurgeParams invoke() {
			nameArray = null;
			statusArray = null;
			dateCreatedMinThreshold = null;
			isPreview = null;
			for (Map.Entry<String, String> entry : config.entrySet()) {
				if (PurgeCartVariableNames.STATUS.toString().equals(
						entry.getKey())) {
					String[] temp = entry.getValue().split(",");
					statusArray = new FSOrderStatus[temp.length];
					int index = 0;
					for (String name : temp) {
						FSOrderStatus orderStatus = FSOrderStatus
								.getInstance(name);
						statusArray[index] = orderStatus;
						index++;
					}
				}
				if (PurgeCartVariableNames.NAME.toString().equals(
						entry.getKey())) {
					nameArray = entry.getValue().split(",");
				}
				if (PurgeCartVariableNames.SECONDS_OLD.toString().equals(
						entry.getKey())) {
					Long secondsOld = Long.parseLong(entry.getValue());
					dateCreatedMinThreshold = new Date(SystemTime.asMillis()
							- (secondsOld * 1000));
				}
				if (PurgeCartVariableNames.IS_PREVIEW.toString().equals(
						entry.getKey())) {
					isPreview = Boolean.parseBoolean(entry.getValue());
				}
			}
			return this;
		}
	}

}
